package cn.com.cifi.mars.service.impl;

import cn.com.cifi.mars.bean.bo.StartAndEndTimeBO;
import cn.com.cifi.mars.bean.bo.returnPlan.CombinationProductDataBO;
import cn.com.cifi.mars.bean.dto.ProjectByStagesDto;
import cn.com.cifi.mars.bean.vo.returnPlan.ReturnPlanDetailMonthData;
import cn.com.cifi.mars.bean.vo.returnPlan.ReturnPlanDetailYearData;
import cn.com.cifi.mars.bean.vo.returnPlan.SignAndReturnVo;
import cn.com.cifi.mars.bean.vo.returnPlan.returnReport.ReturnPlanReport;
import cn.com.cifi.mars.bean.vo.returnPlan.returnReport.ReturnReportOrgBasicsVo;
import cn.com.cifi.mars.bean.vo.returnPlan.returnReport.ReturnReportVo;
import cn.com.cifi.mars.common.exception.MsgException;
import cn.com.cifi.mars.constant.CodeEnum;
import cn.com.cifi.mars.constant.IsDeleteEnum;
import cn.com.cifi.mars.constant.OrgTypeEunm;
import cn.com.cifi.mars.entity.*;
import cn.com.cifi.mars.mapper.mars.ProjectByStagesMapper;
import cn.com.cifi.mars.mapper.mars.ProjectMapper;
import cn.com.cifi.mars.mapper.mars.ReturnPlanVersionMapper;
import cn.com.cifi.mars.mapper.mars.SignPlanVersionMapper;
import cn.com.cifi.mars.mapper.wrapper.ReturnPlanVersionDetailWrapper;
import cn.com.cifi.mars.service.ReturnPlanVersionReportService;
import cn.com.cifi.mars.service.ReturnPlanVersionService;
import cn.com.cifi.mars.service.StagePartNersService;
import cn.com.cifi.mars.util.*;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 回款计划报表
 * @author: JingYuanXiang
 * @date: 2020/12/18 10:28
 */
@Service
public class ReturnPlanVersionReportServiceImpl implements ReturnPlanVersionReportService {

    @Autowired
    private ReturnPlanVersionService returnPlanVersionService;
    @Autowired
    private ReturnPlanVersionMapper returnPlanVersionMapper;
    @Autowired
    private ProjectMapper projectMapper;
    @Autowired
    private ProjectByStagesMapper projectByStagesMapper;
    @Autowired
    private ReturnPlanVersionDetailWrapper returnPlanVersionDetailWrapper;
    @Autowired
    private StagePartNersService stagePartNersService;
    @Autowired
    private SignPlanVersionMapper signPlanVersionMapper;

    /**
     * 获取回款计划导出数据
     * @param versionId
     * @return
     */
    @Override
    public ReturnPlanReport getReturnPlanReportByVersionId(String versionId) {
        if(StringUtils.isBlank(versionId)){
            throw new MsgException(CodeEnum.REQUEST_PARAM_NOT_FULL_ERROR);
        }
        //查询版本
        ReturnPlanVersion returnPlanVersion = returnPlanVersionMapper.selectById(versionId);
        if(null == returnPlanVersion || returnPlanVersion.getIsDelete() == IsDeleteEnum.YES.getKey()){
            throw new MsgException(CodeEnum.NOT_RETURN_PLAN_VERSION_ERROR);
        }
        ProjectByStagesDto stage = projectByStagesMapper.selectByOrgdepid(returnPlanVersion.getStageId());
        //获取项目数据
        MdmProject mdmProject = projectMapper.selectByProjectId(returnPlanVersion.getProjectId(), IsDeleteEnum.NO.getKey());
        //获取回款计划报表组织基础数据
        ReturnReportOrgBasicsVo orgBasicsVo = new ReturnReportOrgBasicsVo(mdmProject.getProjectId(),mdmProject.getProjectCode(), mdmProject.getProjectName());
        //获取回款计划详情列表
        List<ReturnPlanVersionDetail> returnPlanDetailList = returnPlanVersionDetailWrapper.selectByVersionId(versionId,IsDeleteEnum.NO.getKey());

        //获取报表名称
        String versionName = mdmProject.getProjectName() + stage.getOrgname()+"回款计划-"+ VersionNameUtils.getVersionName(returnPlanVersion)
                + "-" +LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyyMMddHH");;
        //获取回款周期数据
        StartAndEndTimeBO startAndEndTimeBO = getStartAndEndTimeBO(returnPlanDetailList);
        //获取回款计划报表数据
        List<ReturnReportVo> voList = this.ReturnReportVoList(startAndEndTimeBO, orgBasicsVo, returnPlanVersion,returnPlanDetailList);

        ReturnPlanReport returnPlanReport = new ReturnPlanReport();
        returnPlanReport.setReportName(versionName);
        returnPlanReport.setStartAndEndTimeBO(startAndEndTimeBO);
        returnPlanReport.setReturnExportVoList(voList);
        return returnPlanReport;
    }


    /**
     * 获取项目全盘回款计划导出数据
     * @param projectId 项目id
     * @return
     */
    @Override
    public ReturnPlanReport getReturnPlanReportByProjectId(String projectId) {
        if(StringUtils.isBlank(projectId)){
            throw new MsgException(CodeEnum.REQUEST_PARAM_NOT_FULL_ERROR);
        }
        //获取项目数据
        MdmProject mdmProject = projectMapper.selectByProjectId(projectId, IsDeleteEnum.NO.getKey());
        //获取回款计划报表组织基础数据
        ReturnReportOrgBasicsVo orgBasicsVo = new ReturnReportOrgBasicsVo(mdmProject.getProjectId(),mdmProject.getProjectCode(), mdmProject.getProjectName());
        //获取全盘版本列表
        List<ReturnPlanVersion> overallVersionList = returnPlanVersionService.getProjectOverallVersionList(projectId);
        //排序
        overallVersionList = ListUtils.sortByStrList(overallVersionList,ListUtils.stageNameList, ReturnPlanVersion::getStageName);
        //获取全盘版本id列表
        List<String> overallVersionIdList = overallVersionList.stream().map(ReturnPlanVersion::getId).collect(Collectors.toList());
        //获取回款计划详情列表
        List<ReturnPlanVersionDetail> returnPlanDetailList = returnPlanVersionDetailWrapper.selectByVersionIdList(overallVersionIdList,IsDeleteEnum.NO.getKey());

        //获取回款周期数据
        StartAndEndTimeBO startAndEndTimeBO = getStartAndEndTimeBO(returnPlanDetailList);
        //获取项目全盘回款计划报表数据
        List<ReturnReportVo> voList = getProjectReturnReportVoList(startAndEndTimeBO,orgBasicsVo,overallVersionList,returnPlanDetailList);
        //报表名称
        String reportName = mdmProject.getProjectName()+"全盘回款计划-".concat(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHH")));

        ReturnPlanReport returnPlanReport = new ReturnPlanReport();
        returnPlanReport.setReportName(reportName);
        returnPlanReport.setStartAndEndTimeBO(startAndEndTimeBO);
        returnPlanReport.setReturnExportVoList(voList);
        return returnPlanReport;
    }

    /**
     * 获取项目全盘回款计划报表数据
     * @param startAndEndTimeBO 回款周期数据
     * @param orgBasicsVo 组织基础数据
     * @param overallVersionList 全盘回款计划版本列表
     * @param returnPlanDetailList 回款计划详情列表
     * @return
     */
    private List<ReturnReportVo> getProjectReturnReportVoList(StartAndEndTimeBO startAndEndTimeBO,ReturnReportOrgBasicsVo orgBasicsVo, List<ReturnPlanVersion> overallVersionList, List<ReturnPlanVersionDetail> returnPlanDetailList) {
        List<ReturnReportVo> vosList = new ArrayList<>();
        //循环回款款计划版本列表
        for (ReturnPlanVersion returnPlanVersion : overallVersionList){
            List<ReturnPlanVersionDetail> returnPlanDetails = returnPlanDetailList.stream().filter(s -> returnPlanVersion.getId().equals(s.getVersionId())).collect(Collectors.toList());
            //获取回款计划报表数据
            List<ReturnReportVo> vos = this.ReturnReportVoList(startAndEndTimeBO,orgBasicsVo,returnPlanVersion,returnPlanDetails);
            vosList.addAll(vos);
        }
        //获取分期层级数据
        List<ReturnReportVo> stageVos = vosList.stream().filter(s -> OrgTypeEunm.ORG_STAGE.getKey().equals(s.getType())).collect(Collectors.toList());
        //汇总计算签约与回款
        SignAndReturnVo signAndReturn = summarySignAndReturn(stageVos);
        //汇总年度数据
        List<ReturnPlanDetailYearData> yearDataList = summaryYearDataList(stageVos);
        //汇总计算月度数据列表
        List<ReturnPlanDetailMonthData> monthDataList = summaryMonthDataList(stageVos);

        ReturnReportVo vo = new ReturnReportVo();
        vo.setId(orgBasicsVo.getProjectId());
        vo.setPid("0");
        vo.setType(OrgTypeEunm.ORG_PRODUCTF.getKey());
        vo.setOrgBasicsVo(orgBasicsVo);
        vo.setSignAndReturn(signAndReturn);
        vo.setYearDataList(yearDataList);
        vo.setMonthDataList(monthDataList);

        List<ReturnReportVo> voList = new ArrayList<>();
        voList.add(vo);
        voList.addAll(vosList);
        return voList;
    }

    /**
     * 获取回款计划报表数据
     * @param startAndEndTimeBO 回款周期数据
     * @param returnReportOrgBasicsVo 组织基础数据
     * @param returnPlanVersion 回款计划版本
     * @param returnPlanDetailList 回款计划详情列表
     * @return
     */
    private List<ReturnReportVo> ReturnReportVoList(StartAndEndTimeBO startAndEndTimeBO, ReturnReportOrgBasicsVo returnReportOrgBasicsVo, ReturnPlanVersion returnPlanVersion, List<ReturnPlanVersionDetail> returnPlanDetailList) {
        ProjectByStagesDto stage = projectByStagesMapper.selectByOrgdepid(returnPlanVersion.getStageId());
        if (null == stage) {
            throw new MsgException(CodeEnum.STAGE_NON_EXISTENT);
        }
        //所属时间
        LocalDateTime affiliationTime = LocalDateTimeUtils.toLocalDateTime(returnPlanVersion.getAffiliationMonth());
        //获取分期基础数据
        ReturnReportOrgBasicsVo orgBasicsVo = getReturnReportOrgBasicsVo(returnPlanVersion.getStageId(), returnPlanVersion.getAffiliationMonth(), returnReportOrgBasicsVo);
        //获取组合业态数据
        CombinationProductDataBO combinationProductData = returnPlanVersionService.getCombinationProductData(returnPlanVersion.getSignPlanVersionId());

        //以组团id和组合业态分组,(key:组团ID，(key:组合业态编码，value:回款计划详情))
        Map<String, Map<String, List<ReturnPlanVersionDetail>>> returnPlanDetailByGroupIdMap = returnPlanDetailList.stream()
                .collect(Collectors.groupingBy(ReturnPlanVersionDetail::getGroupId, Collectors.groupingBy(ReturnPlanVersionDetail::getCombinationProductCode)));

        List<ReturnReportVo> voList = new ArrayList<>();
        List<ReturnReportVo> stageVoList = new ArrayList<>();
        List<ReturnReportVo> groupVoList = new ArrayList<>();
        List<ReturnReportVo> productVoList = new ArrayList<>();
        for (String groupId : returnPlanDetailByGroupIdMap.keySet()){
            List<ReturnReportVo> productVos = new ArrayList<>();
            String groupNmae = null;

            Map<String, List<ReturnPlanVersionDetail>> returnPlanDetailMap = returnPlanDetailByGroupIdMap.get(groupId);
            for (String combinationProductCode : returnPlanDetailMap.keySet()){
                List<ReturnPlanVersionDetail> returnPlanDetails = returnPlanDetailMap.get(combinationProductCode);

                //获取结转日期
                LocalDateTime carryOverTime = combinationProductData.getCarryOverTime(groupId,combinationProductCode);
                //获取总货值
                BigDecimal totalValue = combinationProductData.getTotalValue(groupId,combinationProductCode);
                //获取签约与回款
                SignAndReturnVo signAndReturn = returnPlanVersionService.getSignAndReturn(totalValue,affiliationTime,returnPlanDetails);
                //年度数据列表
                List<ReturnPlanDetailYearData> yearDataList = new ArrayList<>();
                //月度数据列表
                List<ReturnPlanDetailMonthData> monthDataList = new ArrayList<>();
                //循环回款周期时间
                for (int year = startAndEndTimeBO.getStartDate().getYear(); year <= startAndEndTimeBO.getEndDate().getYear(); year++) {
                    //获取年回款计划详情列表
                    int finalYear = year;
                    List<ReturnPlanVersionDetail> yearReturnPlanDetailList = returnPlanDetails.stream()
                            .filter(s -> finalYear == s.getReturnTime().getYear())
                            .sorted(Comparator.comparing(ReturnPlanVersionDetail::getReturnTime))
                            .collect(Collectors.toList());

                    //回款详情数据补充
                    ReturnPlanVersionDetail earlyMonthData = returnPlanVersionService.getEarlyMonthDataSupplement(returnPlanDetails,finalYear);
                    ReturnPlanVersionDetail finalMonthData = returnPlanVersionService.getFinalMonthDataSupplement(returnPlanDetails,finalYear);
                    //获取年度数据
                    ReturnPlanDetailYearData yearData = returnPlanVersionService.getYearData(year,affiliationTime,yearReturnPlanDetailList, earlyMonthData,finalMonthData);
                    //获取月度数据列表
                    List<ReturnPlanDetailMonthData> monthDatas = returnPlanVersionService.getMonthDataList(year, affiliationTime,yearReturnPlanDetailList, earlyMonthData,finalMonthData);
                    yearDataList.add(yearData);
                    monthDataList.addAll(monthDatas);
                }

                ReturnPlanVersionDetail returnPlanDetail = returnPlanDetails.get(0);
                groupNmae = returnPlanDetail.getGroupName();

                ReturnReportVo vo = new ReturnReportVo();
                vo.setId(returnPlanDetail.getId());
                vo.setPid(returnPlanDetail.getGroupId());
                vo.setType(OrgTypeEunm.ORG_PRODUCT.getKey());
                vo.setOrgBasicsVo(orgBasicsVo);
                vo.setGroupName(groupNmae);
                vo.setProProductCode(returnPlanDetail.getProProductCode());
                vo.setProProductName(returnPlanDetail.getProProductType());
                vo.setProductCode(returnPlanDetail.getProductCode());
                vo.setProductName(returnPlanDetail.getProductName());
                vo.setBusinessTypeName(returnPlanDetail.getBusinessTypeName());
                vo.setFreeTypeName(returnPlanDetail.getFreeTypeName());
                vo.setProTypeName(returnPlanDetail.getProTypeName());
                vo.setCarryOverTimeStr(null == carryOverTime ? null : LocalDateTimeUtils.formatTime(carryOverTime, DateUtils.DATE_SMALL_STR));
                vo.setSignAndReturn(signAndReturn);
                vo.setYearDataList(yearDataList);
                vo.setMonthDataList(monthDataList);
                productVos.add(vo);
                productVoList.add(vo);
            }
            //汇总计算签约与回款
            SignAndReturnVo signAndReturn = summarySignAndReturn(productVos);
            //汇总年度数据
            List<ReturnPlanDetailYearData> yearDataList = summaryYearDataList(productVos);
            //汇总计算月度数据列表
            List<ReturnPlanDetailMonthData> monthDataList = summaryMonthDataList(productVos);

            ReturnReportVo vo = new ReturnReportVo();
            vo.setId(groupId);
            vo.setPid(returnPlanVersion.getStageId());
            vo.setType(OrgTypeEunm.ORG_GROUP.getKey());
            vo.setOrgBasicsVo(orgBasicsVo);
            vo.setGroupName(groupNmae);
            vo.setSignAndReturn(signAndReturn);
            vo.setYearDataList(yearDataList);
            vo.setMonthDataList(monthDataList);
            groupVoList.add(vo);
        }
        //汇总计算签约与回款
        SignAndReturnVo signAndReturn = summarySignAndReturn(groupVoList);
        //汇总年度数据
        List<ReturnPlanDetailYearData> yearDataList = summaryYearDataList(groupVoList);
        //汇总计算月度数据列表
        List<ReturnPlanDetailMonthData> monthDataList = summaryMonthDataList(groupVoList);

        ReturnReportVo vo = new ReturnReportVo();
        vo.setId(stage.getOrgdepid());
        vo.setPid(stage.getParentOrgid());
        vo.setType(OrgTypeEunm.ORG_STAGE.getKey());
        vo.setOrgBasicsVo(orgBasicsVo);
        vo.setSignAndReturn(signAndReturn);
        vo.setYearDataList(yearDataList);
        vo.setMonthDataList(monthDataList);
        stageVoList.add(vo);

        //排序
        groupVoList = ListUtils.sortByStrList(groupVoList,ListUtils.groupNameList, ReturnReportVo::getGroupName);
        for(ReturnReportVo stageVo : stageVoList){
            voList.add(stageVo);
            for(ReturnReportVo groupVo : groupVoList){
                if(stageVo.getId().equals(groupVo.getPid())){
                    voList.add(groupVo);
                    for(ReturnReportVo productVo : productVoList){
                        if(groupVo.getId().equals(productVo.getPid())){
                            voList.add(productVo);
                        }
                    }
                }
            }
        }
        return voList;
    }


    /**
     * 汇总计算签约与回款
     * @param voList 回款计划一年数据列表
     * @return
     */
    private SignAndReturnVo summarySignAndReturn(List<ReturnReportVo> voList) {
        SignAndReturnVo vo = new SignAndReturnVo();

        //总货值
        BigDecimal totalValue = BigDecimal.ZERO;
        //累计已售
        BigDecimal accumulativeSold = BigDecimal.ZERO;
        //累计已回款
        BigDecimal accumulativeReturn = BigDecimal.ZERO;
        for(ReturnReportVo yearDataVo : voList){
            SignAndReturnVo signAndReturn = yearDataVo.getSignAndReturn();
            totalValue = totalValue.add(signAndReturn.getTotalValue());
            accumulativeSold = accumulativeSold.add(signAndReturn.getAccumulativeSold());
            accumulativeReturn = accumulativeReturn.add(signAndReturn.getAccumulativeReturn());
        }
        //已签未回(累计已售 - 累计已回款)
        BigDecimal signNotReturn = accumulativeSold.subtract(accumulativeReturn);
        //未签未回(总货值 - 累计已售)
        BigDecimal notSignNotReturn = totalValue.subtract(accumulativeSold);
        //累计签约回款率(累计已回款/累计已售)
        BigDecimal signReturnRate = BigDecimalUtils.divBigDecimal(accumulativeReturn,accumulativeSold,4);

        vo.setTotalValue(totalValue);
        vo.setAccumulativeSold(accumulativeSold);
        vo.setAccumulativeReturn(accumulativeReturn);
        vo.setSignNotReturn(signNotReturn);
        vo.setNotSignNotReturn(notSignNotReturn);
        vo.setSignReturnRate(signReturnRate);
        return vo;
    }

    /**
     * 汇总年度数据
     * @param voList 回款计划一年数据列表
     * @return
     */
    private List<ReturnPlanDetailYearData> summaryYearDataList(List<ReturnReportVo> voList) {
        List<ReturnPlanDetailYearData> detailYearDataLsit = new ArrayList<>();

        List<ReturnPlanDetailYearData> yearDataList = voList.stream()
                .flatMap(s -> s.getYearDataList().stream())
                .collect(Collectors.toList());

        //获取年度列表
        List<Integer> yearlist = yearDataList.stream().map(ReturnPlanDetailYearData::getYear).distinct().collect(Collectors.toList());
        for (int year : yearlist){
            List<ReturnPlanDetailYearData> yearDatas = yearDataList
                    .stream().filter(s -> s.getYear() == year )
                    .collect(Collectors.toList());
            if(CollectionUtils.isEmpty(yearDatas)){
                continue;
            }

            //年度签约
            BigDecimal yearSign = BigDecimal.ZERO;
            //年度实际数-增量回款
            BigDecimal annualActualIncrementalReturn  = BigDecimal.ZERO;
            //年度实际数-存量回款
            BigDecimal annualActualStoreReturn  = BigDecimal.ZERO;
            //年度测算数-增量回款
            BigDecimal annualCalculateIncrementalReturn  = BigDecimal.ZERO;
            //年度测算数-存量回款
            BigDecimal annualCalculateStoreReturn  = BigDecimal.ZERO;
            //年度调整数-增量回款
            BigDecimal annualAdjustIncrementalReturn  = BigDecimal.ZERO;
            //年度调整数-存量回款
            BigDecimal annualAdjustStoreReturn  = BigDecimal.ZERO;
            //年度已签未回回款数
            BigDecimal yearSignNotReturn  = BigDecimal.ZERO;
            //年度回款合计-增量回款
            BigDecimal annualTotalIncrementalReturn  = BigDecimal.ZERO;
            //年度回款合计-存量回款
            BigDecimal annualTotalStoreReturn  = BigDecimal.ZERO;
            //年度回款合计-回款合计
            BigDecimal annualTotalReturnTotal  = BigDecimal.ZERO;
            //年初应收账款
            BigDecimal yearEarlyReceivable = BigDecimal.ZERO;
            //年初应退账款
            BigDecimal yearEarlyRefund = BigDecimal.ZERO;
            //年度回款合计-年末应收账款
            BigDecimal annualTotalYearEndReceivable = BigDecimal.ZERO;
            for (ReturnPlanDetailYearData yearData :yearDatas){
                yearSign = yearSign.add(yearData.getYearSign());
                annualActualIncrementalReturn = annualActualIncrementalReturn.add(yearData.getAnnualActualIncrementalReturn());
                annualActualStoreReturn = annualActualStoreReturn.add(yearData.getAnnualActualStoreReturn());
                annualCalculateIncrementalReturn = annualCalculateIncrementalReturn.add(yearData.getAnnualCalculateIncrementalReturn());
                annualCalculateStoreReturn = annualCalculateStoreReturn.add(yearData.getAnnualCalculateStoreReturn());
                annualAdjustIncrementalReturn = annualAdjustIncrementalReturn.add(yearData.getAnnualAdjustIncrementalReturn());
                annualAdjustStoreReturn = annualAdjustStoreReturn.add(yearData.getAnnualAdjustStoreReturn());
                yearSignNotReturn = yearSignNotReturn.add(yearData.getYearSignNotReturn());
                annualTotalIncrementalReturn = annualTotalIncrementalReturn.add(yearData.getAnnualTotalIncrementalReturn());
                annualTotalStoreReturn = annualTotalStoreReturn.add(yearData.getAnnualTotalStoreReturn());
                annualTotalReturnTotal = annualTotalReturnTotal.add(yearData.getAnnualTotalReturnTotal());
                yearEarlyReceivable = yearEarlyReceivable.add(yearData.getYearEarlyReceivable());
                yearEarlyRefund = yearEarlyRefund.add(yearData.getYearEarlyRefund());
                annualTotalYearEndReceivable = annualTotalYearEndReceivable.add(yearData.getAnnualTotalYearEndReceivable());
            }
            ReturnPlanDetailYearData detailYearData = new ReturnPlanDetailYearData();
            detailYearData.setYear(year);
            detailYearData.setYearSign(yearSign);
            detailYearData.setAnnualActualIncrementalReturn(annualActualIncrementalReturn);
            detailYearData.setAnnualActualStoreReturn(annualActualStoreReturn);
            detailYearData.setAnnualCalculateIncrementalReturn(annualCalculateIncrementalReturn);
            detailYearData.setAnnualCalculateStoreReturn(annualCalculateStoreReturn);
            detailYearData.setAnnualAdjustIncrementalReturn(annualAdjustIncrementalReturn);
            detailYearData.setAnnualAdjustStoreReturn(annualAdjustStoreReturn);
            detailYearData.setYearSignNotReturn(yearSignNotReturn);
            detailYearData.setAnnualTotalIncrementalReturn(annualTotalIncrementalReturn);
            detailYearData.setAnnualTotalStoreReturn(annualTotalStoreReturn);
            detailYearData.setAnnualTotalReturnTotal(annualTotalReturnTotal);
            detailYearData.setYearEarlyReceivable(yearEarlyReceivable);
            detailYearData.setYearEarlyRefund(yearEarlyRefund);
            detailYearData.setAnnualTotalYearEndReceivable(annualTotalYearEndReceivable);
            detailYearDataLsit.add(detailYearData);
        }
        return detailYearDataLsit;
    }

    /**
     * 汇总计算月度数据列表
     * @param voList
     * @return
     */
    private List<ReturnPlanDetailMonthData> summaryMonthDataList(List<ReturnReportVo> voList) {
        List<ReturnPlanDetailMonthData> summaryMonthDataList = new ArrayList<>();

        List<ReturnPlanDetailMonthData> monthDataList = voList.stream()
                .flatMap(s -> s.getMonthDataList().stream())
                .collect(Collectors.toList());

        //获取年度列表
        List<Integer> yearlist = monthDataList.stream().sorted(Comparator.comparing(ReturnPlanDetailMonthData::getYear)).map(ReturnPlanDetailMonthData::getYear).distinct().collect(Collectors.toList());
        for(int year : yearlist){
            //1月期初应收
            BigDecimal beginningReceivable = BigDecimal.ZERO;
            for (int i = 1; i <=12 ; i++) {
                int month = i;
                //获取指定月份月度数据列表
                List<ReturnPlanDetailMonthData> monthDatas = monthDataList
                        .stream().filter(s -> s.getYear() == year && s.getMonth() == month)
                        .collect(Collectors.toList());
                ReturnPlanDetailMonthData monthData = new ReturnPlanDetailMonthData();
                monthData.setYear(year);
                monthData.setMonth(i);
                if (CollectionUtils.isEmpty(monthDatas)){
                    monthData.initialize();
                    summaryMonthDataList.add(monthData);
                    continue;
                }
                //计算1月期初应收
                if(1 == i){
                    beginningReceivable = monthDatas.stream().map(ReturnPlanDetailMonthData::getMonthEarlyReceivable).reduce(BigDecimal.ZERO, BigDecimal::add);
                }

                //月初应收账款
                BigDecimal monthEarlyReceivable = BigDecimal.ZERO;
                //月度签约
                BigDecimal monthSign = BigDecimal.ZERO;
                //月度实际数-增量回款
                BigDecimal monthlyActualIncrementalReturn = BigDecimal.ZERO;
                //月度实际数-存量回款
                BigDecimal monthlyActualStoreReturn = BigDecimal.ZERO;
                //月度测算数-增量回款
                BigDecimal monthlyCalculateIncrementalReturn = BigDecimal.ZERO;
                //月度测算数-存量回款
                BigDecimal monthlyCalculateStoreReturn = BigDecimal.ZERO;
                //月度调整数-增量回款
                BigDecimal monthlyAdjustIncrementalReturn = BigDecimal.ZERO;
                //月度调整数-存量回款
                BigDecimal monthlyAdjustStoreReturn = BigDecimal.ZERO;
                //月度已签未回回款数
                BigDecimal monthSignNotReturn = BigDecimal.ZERO;
                //期初应退回款数
                BigDecimal refundable = BigDecimal.ZERO;
                //月度回款合计-增量回款
                BigDecimal monthlyTotalIncrementalReturn = BigDecimal.ZERO;
                //月度回款合计-存量回款
                BigDecimal monthlyTotalStoreReturn = BigDecimal.ZERO;
                //月度回款合计-回款合计
                BigDecimal monthlyTotalReturnTotal = BigDecimal.ZERO;
                //月度回款合计-月末应收账款
                BigDecimal monthlyTotalMonthEndReceivable = BigDecimal.ZERO;
                //累计年度签约合计
                BigDecimal yearSignAmountTotal = BigDecimal.ZERO;
                //累计签约合计
                BigDecimal signAmountTotal = BigDecimal.ZERO;
                //累计年度回款合计
                BigDecimal yearReturnAmountTotal = BigDecimal.ZERO;
                //累计回款合计
                BigDecimal returnAmountTotal = BigDecimal.ZERO;

                for(ReturnPlanDetailMonthData returnPlanDetailMonthData : monthDatas){
                    monthEarlyReceivable = monthEarlyReceivable.add(returnPlanDetailMonthData.getMonthEarlyReceivable());
                    monthSign = monthSign.add(returnPlanDetailMonthData.getMonthSign());
                    monthlyActualIncrementalReturn = monthlyActualIncrementalReturn.add(returnPlanDetailMonthData.getMonthlyActualIncrementalReturn());
                    monthlyActualStoreReturn = monthlyActualStoreReturn.add(returnPlanDetailMonthData.getMonthlyActualStoreReturn());
                    monthlyCalculateIncrementalReturn = monthlyCalculateIncrementalReturn.add(returnPlanDetailMonthData.getMonthlyCalculateIncrementalReturn());
                    monthlyCalculateStoreReturn = monthlyCalculateStoreReturn.add(returnPlanDetailMonthData.getMonthlyCalculateStoreReturn());
                    monthlyAdjustIncrementalReturn = monthlyAdjustIncrementalReturn.add(returnPlanDetailMonthData.getMonthlyAdjustIncrementalReturn());
                    monthlyAdjustStoreReturn = monthlyAdjustStoreReturn.add(returnPlanDetailMonthData.getMonthlyAdjustStoreReturn());
                    monthSignNotReturn = monthSignNotReturn.add(returnPlanDetailMonthData.getMonthSignNotReturn());
                    refundable = refundable.add(returnPlanDetailMonthData.getRefundable());
                    monthlyTotalIncrementalReturn = monthlyTotalIncrementalReturn.add(returnPlanDetailMonthData.getMonthlyTotalIncrementalReturn());
                    monthlyTotalStoreReturn = monthlyTotalStoreReturn.add(returnPlanDetailMonthData.getMonthlyTotalStoreReturn());
                    monthlyTotalReturnTotal = monthlyTotalReturnTotal.add(returnPlanDetailMonthData.getMonthlyTotalReturnTotal());
                    monthlyTotalMonthEndReceivable = monthlyTotalMonthEndReceivable.add(returnPlanDetailMonthData.getMonthlyTotalMonthEndReceivable());
                    yearSignAmountTotal = yearSignAmountTotal.add(returnPlanDetailMonthData.getYearSignAmountTotal());
                    signAmountTotal = signAmountTotal.add(returnPlanDetailMonthData.getSignAmountTotal());
                    yearReturnAmountTotal = yearReturnAmountTotal.add(returnPlanDetailMonthData.getYearReturnAmountTotal());
                    returnAmountTotal = returnAmountTotal.add(returnPlanDetailMonthData.getReturnAmountTotal());
                }
                //月初应收账款
                monthData.setMonthEarlyReceivable(monthEarlyReceivable);
                //月度签约
                monthData.setMonthSign(monthSign);
                //月度实际数-增量回款
                monthData.setMonthlyActualIncrementalReturn(monthlyActualIncrementalReturn);
                //月度实际数-存量回款
                monthData.setMonthlyActualStoreReturn(monthlyActualStoreReturn);
                //月度测算数-增量回款
                monthData.setMonthlyCalculateIncrementalReturn(monthlyCalculateIncrementalReturn);
                //月度测算数-存量回款
                monthData.setMonthlyCalculateStoreReturn(monthlyCalculateStoreReturn);
                //月度调整数-增量回款
                monthData.setMonthlyAdjustIncrementalReturn(monthlyAdjustIncrementalReturn);
                //月度调整数-存量回款
                monthData.setMonthlyAdjustStoreReturn(monthlyAdjustStoreReturn);
                //月度已签未回回款数
                monthData.setMonthSignNotReturn(monthSignNotReturn);
                //期初应退回款数
                monthData.setRefundable(refundable);
                //月度回款合计-增量回款
                monthData.setMonthlyTotalIncrementalReturn(monthlyTotalIncrementalReturn);
                //月度回款合计-存量回款
                monthData.setMonthlyTotalStoreReturn(monthlyTotalStoreReturn);
                //月度回款合计-回款合计
                monthData.setMonthlyTotalReturnTotal(monthlyTotalReturnTotal);
                //月度回款合计-月末应收账款
                monthData.setMonthlyTotalMonthEndReceivable(monthlyTotalMonthEndReceivable);
                //累计年度签约合计
                monthData.setYearSignAmountTotal(yearSignAmountTotal);
                //累计签约合计
                monthData.setSignAmountTotal(signAmountTotal);
                //累计年度回款合计
                monthData.setYearReturnAmountTotal(yearReturnAmountTotal);
                //累计回款合计
                monthData.setReturnAmountTotal(returnAmountTotal);
                //累计签约回款率(开售月累计到当月回款合计/开售月累计到累计当月签约金额)
                BigDecimal signReturnRate = BigDecimalUtils.divBigDecimal(returnAmountTotal,signAmountTotal,5);
                //年度综合回款率(从当年1月累计到当月回款合计/(当年1月的期初应收 + 从当年1月累计到累计当月签约金额)
                BigDecimal annualOverallReturnRate = BigDecimalUtils
                        .divBigDecimal(yearReturnAmountTotal,beginningReceivable.add(yearSignAmountTotal),5);
                //累计签约回款率
                monthData.setSignReturnRate(signReturnRate);
                //年度综合回款率
                monthData.setAnnualOverallReturnRate(annualOverallReturnRate);
                summaryMonthDataList.add(monthData);
            }
        }
        return summaryMonthDataList;
    }


    /**
     * 获取回款周期时间数据
     * @param returnPlanDetailList 回款详情列表
     * @return
     */
    private StartAndEndTimeBO getStartAndEndTimeBO(List<ReturnPlanVersionDetail> returnPlanDetailList) {
        StartAndEndTimeBO bo = new StartAndEndTimeBO();

        LocalDateTime startDate = returnPlanDetailList.stream()
                .min(Comparator.comparing(ReturnPlanVersionDetail::getReturnTime))
                .orElse(new ReturnPlanVersionDetail())
                .getReturnTime();
        startDate = LocalDateTime.of(startDate.getYear(), 1, 1, 0, 0);

        LocalDateTime endDate = returnPlanDetailList.stream()
                .max(Comparator.comparing(ReturnPlanVersionDetail::getReturnTime))
                .orElse(new ReturnPlanVersionDetail())
                .getReturnTime();
        endDate = LocalDateTime.of(endDate.getYear(), 12, 1, 0, 0);

        bo.setStartDate(startDate);
        bo.setEndDate(endDate);
        return bo;
    }

    /**
     * 获取分期基础数据
     * @param stageId
     * @param yearMonth
     * @param returnReportOrgBasicsVo
     * @return
     */
    private ReturnReportOrgBasicsVo getReturnReportOrgBasicsVo(String stageId, String yearMonth, ReturnReportOrgBasicsVo returnReportOrgBasicsVo) {
        ReturnReportOrgBasicsVo orgBasicsVo = new ReturnReportOrgBasicsVo();

        StagePartNers stagePartners = stagePartNersService.getStagePartnersByProjectFid(stageId);
        DmDmValueReport dmDmValueReport = signPlanVersionMapper.selectDmValueReportByStageId(stageId, yearMonth);

        orgBasicsVo.setStageCode(stagePartners.getStageCode());
        orgBasicsVo.setStageName(stagePartners.getStageName());
        //旭辉权益比例
        orgBasicsVo.setEquityRatio(stagePartners.getEquityRatio());
        //营销操盘方式
        orgBasicsVo.setOpmarketing(stagePartners.getIsOpMarketing());
        //是否并表
        orgBasicsVo.setIsAndTable(stagePartners.getPartNerIsAndTable() == null ? 0 : Integer.valueOf(stagePartners.getPartNerIsAndTable()));
        if (null != dmDmValueReport) {
            //现房销售
            orgBasicsVo.setExistingHouses(dmDmValueReport.getIsExistRoomSale());
        }
        orgBasicsVo.setProjectId(returnReportOrgBasicsVo.getProjectId());
        orgBasicsVo.setProjectCode(returnReportOrgBasicsVo.getProjectCode());
        orgBasicsVo.setProjectName(returnReportOrgBasicsVo.getProjectName());
        return orgBasicsVo;
    }
}
